﻿using System.Windows;

namespace Trentacular.SharePoint.Deployment.Util
{
    public static class DependencyObjectExtensions
    {
        private delegate object GetValueDelegate(DependencyProperty dp);
        private delegate void SetValueDelegate(DependencyProperty dp, object value);
        private delegate void SetKeyValueDelegate(DependencyPropertyKey dp, object value);

        /// <summary>
        /// Returns the current effective value of a dependency property on this instance
        ///     of a System.Windows.DependencyObject. This method is thread-safe.
        /// </summary>
        /// <typeparam name="ReturnType">The type of the returned value.</typeparam>
        /// <param name="Target">The object that is using the extension method.</param>
        /// <param name="Property">The DependencyProperty identifier of the property to retrieve the value for.</param>
        /// <returns>Returns the current effective value.</returns>
        public static T GetThreadSafeValue<T>(this DependencyObject target, DependencyProperty property)
        {
            if (target.Dispatcher.CheckAccess())
                return (T)target.GetValue(property);
            else
                return (T)target.Dispatcher.Invoke(new GetValueDelegate(target.GetValue), new object[] { property });
        }

        /// <summary>
        /// Sets the local value of a dependency property, specified by its dependency
        ///     property identifier. This method is thread-safe.
        /// </summary>
        /// <param name="Target">The object that is using the extension method.</param>
        /// <param name="Property">The identifier of the dependency property to set.</param>
        /// <param name="Value">The new local value.</param>
        public static void SetThreadSafeValue(this DependencyObject target, DependencyProperty property, object value)
        {
            if (target.Dispatcher.CheckAccess())
                target.SetValue(property, value);
            else
                target.Dispatcher.Invoke(new SetValueDelegate(target.SetValue), new object[] { property, value });
        }

        /// <summary>
        /// Sets the local value of a read-only dependency property, specified by the
        ///     System.Windows.DependencyPropertyKey identifier of the dependency property. This method is thread-safe.
        /// </summary>
        /// <param name="Target">The object that is using the extension method.</param>
        /// <param name="PropertyKey"> The System.Windows.DependencyPropertyKey identifier of the property to set.</param>
        /// <param name="Value">The new local value.</param>
        public static void SetThreadSafeValue(this DependencyObject target, DependencyPropertyKey propertyKey, object value)
        {
            if (target.Dispatcher.CheckAccess())
                target.SetValue(propertyKey, value);
            else
                target.Dispatcher.Invoke(new SetKeyValueDelegate(target.SetValue), new object[] { propertyKey, value });
        }
    }
}
